package com.zhaotianhao.springboot_demo_fire.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.zhaotianhao.springboot_demo_fire.common.JsonResult;
import com.zhaotianhao.springboot_demo_fire.entity.Firearms;
import com.zhaotianhao.springboot_demo_fire.entity.FirearmsParts;
import com.zhaotianhao.springboot_demo_fire.entity.Parts;
import com.zhaotianhao.springboot_demo_fire.exception.FirearmException;
import com.zhaotianhao.springboot_demo_fire.service.IFirearmsPartsService;
import com.zhaotianhao.springboot_demo_fire.service.IFirearmsService;
import com.zhaotianhao.springboot_demo_fire.service.IPartsService;
import com.zhaotianhao.springboot_demo_fire.utils.HighLightResultMapper;
import jdk.nashorn.internal.runtime.logging.Logger;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author Z-7
 * @since 2022-03-22
 */
@Logger
@Slf4j
@Controller
@RequestMapping("/firearms")
public class FirearmsController {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private KafkaTemplate kafkaTemplate;
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private IFirearmsPartsService iFirearmsPartsService;
    @Autowired
    private IFirearmsService iFirearmsService;
    @Autowired
    private IPartsService iPartsService;

    @RequestMapping("list")
    public String to_list(@RequestParam(defaultValue = "1")int pageNum, @RequestParam(defaultValue = "3")int pageSize, Model model){
        PageInfo<Firearms> page = iFirearmsService.getPageInfo(pageNum,pageSize);
        log.info("列表信息：{}",page.getList());
        model.addAttribute("page",page);

        return "fire_list";
    }
    @GetMapping("to_edit")
    public String to_edit(Integer id,Model model){
        if (id != null) {
            Firearms firearms = iFirearmsService.getById(id);
            model.addAttribute("fire",firearms);
            // 查询对应的配件 做回显使用
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("firearms",id);
            List<FirearmsParts> list = iFirearmsPartsService.list(queryWrapper);
            List<Integer> partIds = list.stream().map(part -> part.getParts()).collect(Collectors.toList());
            model.addAttribute("list",partIds);
        }
        model.addAttribute("token",UUID.randomUUID().toString());
        model.addAttribute("parts",iPartsService.list());
        return "fire_edit";
    }
    @PostMapping("edit")
    public @ResponseBody JsonResult add(String token,Firearms firearms, Integer partss[]) throws InterruptedException {
        if(!(redisTemplate.opsForValue().setIfAbsent(token,"",10,TimeUnit.MINUTES))){
            log.info("编辑枪械重复提交");
            return JsonResult.faild("请稍等");
        }
        if(true){
            throw new FirearmException(400,"异常");
        }
        log.info("编辑，{}，配件是：{}",firearms,partss);
        Thread.sleep(1000);

        if(firearms.getId() != null){
            // 删除中间表
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("firearms",firearms.getId());
            boolean remove = iFirearmsPartsService.remove(queryWrapper);
        }

        // 主表的添加 或者修改
        boolean save = iFirearmsService.saveOrUpdate(firearms);

        List<Integer> partsId = new ArrayList<>();
        List<FirearmsParts> list = new ArrayList<>();
        for (Integer partId : partss) {
            log.info("配件：{}",partId);
            partsId.add(partId);
            list.add(new FirearmsParts().setParts(partId).setFirearms(firearms.getId()));
        }
        List<Parts> parts = iPartsService.listByIds(partsId);
        String collect = parts.stream().map(s -> s.getName()).collect(Collectors.joining(","));

        // 中间表添加
        boolean flag = iFirearmsPartsService.saveBatch(list);
        if(save && flag){
            // kafka发送消息
            String uuid = UUID.randomUUID().toString();

            kafkaTemplate.send("fire","edit", JSON.toJSONString(firearms.setUuid(uuid).setPartsName(collect)));
            Map<String, Object> map = new HashMap<>();
            map.put("message",firearms.setUuid(uuid).setPartsName(collect));
            map.put("create_time",new Date().getTime());
            map.put("operation","edit");

            // redis备份 防止消息丢失
            redisTemplate.opsForValue().set("message:"+uuid, JSON.toJSONString(map));

            return JsonResult.successd();
        }
        return JsonResult.faild(500,"添加失败，查看日志",firearms);
    }

    @PostMapping("del")
    @Transactional(rollbackFor = {Exception.class})
    public @ResponseBody JsonResult del(Integer id){
        Firearms firearms = iFirearmsService.queryById(id);
        // 删除中间表
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("firearms",id);
        // 删除中间表
        boolean remove = iFirearmsPartsService.remove(queryWrapper);
        log.info("删除，{}",firearms);
        // 删除主表
        boolean flag = iFirearmsService.removeById(id);
        if(remove && flag){
            // kafka发送消息
            String uuid = UUID.randomUUID().toString();
            kafkaTemplate.send("fire","delete",JSON.toJSONString(firearms.setUuid(uuid)));

            Map<String, Object> map = new HashMap<>();
            map.put("message",firearms.setUuid(uuid));
            map.put("create_time",new Date().getTime());
            map.put("operation","delete");

            // redis备份 防止消息丢失
            redisTemplate.opsForValue().set("message:"+uuid, JSON.toJSONString(map));

            return JsonResult.successd();
        }
        return JsonResult.faild(500,"删除失败，查看日志",firearms);
    }

    @RequestMapping("esList")
    public String esList(String search,@RequestParam(defaultValue = "1")int pageNum, @RequestParam(defaultValue = "3")int pageSize, Model model){
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if(StringUtils.hasText(search)){
            boolQuery.must(QueryBuilders.multiMatchQuery(search,"name","partsName"));
        }

        HighlightBuilder.Field name = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
        HighlightBuilder.Field partsName = new HighlightBuilder.Field("partsName").preTags("<span style='color:red'>").postTags("</span>");

        NativeSearchQuery na = new NativeSearchQueryBuilder()
                .withQuery(boolQuery)
                .withHighlightFields(name, partsName)
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
                .withPageable(PageRequest.of(pageNum - 1, pageSize))
                .build();

        AggregatedPage<Firearms> firearms = elasticsearchTemplate.queryForPage(na, Firearms.class, new HighLightResultMapper());

        Page page = new Page(pageNum, pageSize);
        page.setTotal(firearms.getTotalElements());

        PageInfo pageInfo = new PageInfo<>(page);
        pageInfo.setList(firearms.getContent());

        model.addAttribute("page",pageInfo);
        model.addAttribute("search",search);
        return "fire_eslist";
    }
}
